<?php
/**
 * REKS framework is a very lightweight and small footprint PHP 5.3+ Framework.
 * It supports a limited set of features but fully MVC based and Objectoriented.
 * 
 * Copyright (c) 2012, REKS group ( Lars Martin Rørtveit, Andreas Elvatun, Petter Kjelkenes, Pål André Sundt )
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the REKS GROUP nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL "REKS Group" BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @license 3-clause BSD
 * @package reks
 * @author REKS group at Telemark University College
 */
namespace reks\view;


/**
 * ScriptCompiler can add javascripts and css scripts.
 * It can also compile css files and add them to 1 single file. This increases SEO and performance of your site.
 * It can cache the compiled files.
 *
 * @author REKS group at Telemark University College
 * @version 1.0
 */
class ScriptCompiler{
	/**
	 * View reference.
	 * @var reks\View
	 */
	protected $view;
	
	/**
	 * Array of scripts added. Relative path from public
	 * @var array
	 */
	protected $scripts=array();
	
	/**
	 * Supported extensions are js and css
	 * @var string extension, eg. css or js.
	 */
	protected $extension;
	
	/**
	 * Creates a new object of the Script compiler.
	 * @param reks\View $view View instance
	 * @param string $extension Script extension ( eg. css or js )
	 */
	public function __construct($view, $extension){
		$this->view = $view;
		$this->extension = $extension;
	}
	
	/**
	 * Adds a resource.
	 * Example:
	 * <code>
	 * 		$this->js->add('js/jquery.js');
	 * </code>
	 * @param string $resource Resource from the public space. ( Where index.php is )
	 */
	public function add($resource){
		$this->scripts[] = $resource;
		return $this;
	}

	/**
	 * Compiles the scripts in the scripts array,
	 * caches it for amount of seconds
	 * and display the cached version.
	 * @param int $cacheTime Time to cache in seconds, 3600 = 1 hour. Can also be 0 to not cache.
	 */
	public function compile($cacheTime = 3600){
		if (count($this->scripts) == 0)return;
		
		$hash = md5(implode('',array_values($this->scripts)));
		
		$create = true;
		$cF = $this->view->app->PUBLIC_PATH . "/cache/{$hash}.{$this->extension}";
		$src = $this->view->url->asset("cache/{$hash}.{$this->extension}");
		if ($cacheTime){
			if (!file_exists($cF) || filemtime($cF) < (time()-$cacheTime)){
				$create = true;
			}else{
				return $this->show($src);
			}
		}
		
		if ($create){
			$content = '';
			foreach($this->scripts as $script){
				$c = @file_get_contents($this->view->app->PUBLIC_PATH . "/$script");
				if ($c)$content .= $this->compileReferences($c, $script);
			}
			switch($this->extension){
				case 'css':
					$content = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $content);
					$content = str_replace(array("\r\n", "\r", "\n", "\t", '  ', '    ', '    '), '', $content);
					break;
			}	
			$content = '/** Generated by REKS at '.date('d-m-y', time()).' **/' . $content;
					
			file_put_contents($cF, $content);
		}
		
		$this->show($src);
	}
	
	/**
	 * Used to compile references of a css file.
	 * 
	 * Note! JS is not yet supported.
	 * 
	 * It makes relative paths to domain specific paths.
	 * If we have in the css file
	 * background-image('../img/test.png');
	 * This might become
	 * background-image('/img/test.png');
	 * in the cached version of the css file.
	 * @param string $content Content of the script
	 * @param string $script
	 */
	public function compileReferences($content, $script){
		$scriptDir = dirname($this->view->app->PUBLIC_PATH . '/' . $script);
		switch($this->extension){
			case 'js':
				break;
			case 'css':
				preg_match_all('#url.*?\((.*?)\)#is', $content, $matches);
				foreach($matches[1] as $path){
					$path = trim($path,'\'"');
					// If this is a relative reference.
					if (substr($path, 0, 1) != '/' && 
						!strstr($path, '://')
					){
						$newPath = substr(realpath($scriptDir . '/' . $path), strlen($this->view->app->PUBLIC_PATH));
						
						if ($newPath)$content = str_replace($path, '..'.$newPath, $content);		
					}
				}
				break;
		}
		
		return $content;
	}
	/**
	 * Renders the scripts in normal way of just outputting many tags for each file.
	 */
	public function render(){
		foreach($this->scripts as $script){
			$this->show($this->view->url->asset($script));
		}
	}
	/**
	 * Shows a script  based on source. Note public path used.
	 * @param string $src Public path
	 */
	public function show($src){
		switch($this->extension){
			case 'js':
				echo '<script type="text/javascript" src="'.$src.'"></script>';
				break;
			case 'css':
				echo '<link rel="stylesheet" type="text/css" href="'.$src.'" />';
				break;
		}
	}
	
}